package com.cherish.config.security.filter;

import com.cherish.config.jwt.JwtUtils;
import com.cherish.config.security.detailservice.CustomerUserDetailsService;
import com.cherish.config.security.exception.CustomerAuthenionException;
import com.cherish.config.security.exception.ImageException;
import com.cherish.config.security.handler.LoginFailureHandler;
import com.cherish.redis.RedisService;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Author:MQ
 * Date:2024/1/39:40
 *
 * token验证过滤器
 */
@Data
@Component("checkTokenFilter")
public class CheckTokenFilter extends OncePerRequestFilter {
    @Autowired
    private JwtUtils jwtUtils;
    @Autowired
    private CustomerUserDetailsService customerUserDetailsService;
    @Autowired
    private LoginFailureHandler loginFailureHandler;
    @Autowired
    private RedisService redisService;

    @Value("${cherish.loginUrl}")
    private String loginUrl;
    @Value("${cherish.imageUrl}")
    private String imageUrl;

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        if (StringUtils.contains(httpServletRequest.getServletPath(), "swagger")
                || StringUtils.contains(httpServletRequest.getServletPath(), "webjars")
                || StringUtils.contains(httpServletRequest.getServletPath(), "v3")
                || StringUtils.contains(httpServletRequest.getServletPath(), "profile")
                || StringUtils.contains(httpServletRequest.getServletPath(), "swagger-ui")
                || StringUtils.contains(httpServletRequest.getServletPath(), "swagger-resources")
                || StringUtils.contains(httpServletRequest.getServletPath(), "csrf")
                || StringUtils.contains(httpServletRequest.getServletPath(), "favicon")
                || StringUtils.contains(httpServletRequest.getServletPath(), "v2")) {
            filterChain.doFilter(httpServletRequest, httpServletResponse);
        }else{
            try{
                String url = httpServletRequest.getRequestURI();
                // 登录请求才做验证码
                if(url.equals(loginUrl)){
                    // validateImage(httpServletRequest);
                }
                // token验证，登录请求、验证码请求不做登录请求
                if(!url.equals(loginUrl) && !url.equals(imageUrl)){
                    validateToken(httpServletRequest);
                }
            }catch (AuthenticationException e){
                loginFailureHandler.onAuthenticationFailure(httpServletRequest,httpServletResponse,e);
                return;
            }
            filterChain.doFilter(httpServletRequest,httpServletResponse);
        }
    }
    //验证码验证
    private void validateImage(HttpServletRequest request){
        //获取验证码
        String code = request.getParameter("code");
        if(StringUtils.isEmpty(code)){
            throw new ImageException("验证码不能为空!");
        }
        //获取请求的ip
        String ip = request.getRemoteAddr();
        //key
        String key = ip+code;
        //获取redis里面的验证码
        String oldCode = redisService.get(key);
        if(!code.equalsIgnoreCase(oldCode)){
            throw new ImageException("验证码错误!");
        }
    }
    //token验证
    private void validateToken(HttpServletRequest request) throws CustomerAuthenionException {
        //从头部获取token
        String token = request.getHeader("token");
        //如果从头部获取token失败，那么从参数获取
        if(StringUtils.isEmpty(token)){
            token = request.getParameter("token");
        }
        //如果没有获取到token
        if(StringUtils.isEmpty(token)){
            throw new CustomerAuthenionException("token获取失败！");
        }
        //解析token
        String username = jwtUtils.getUsernameFromToken(token);
        if(StringUtils.isEmpty(username)){
            throw new CustomerAuthenionException("token解析失败！");
        }
        //获取用户信息
        UserDetails details = customerUserDetailsService.loadUserByUsername(username);
        if(details == null){
            throw new CustomerAuthenionException("token解析失败！");
        }
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(details,null,details.getAuthorities());
        authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
        //设置到spring security上下文
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
    }
}
